<!DOCTYPE html>
<html lang="zh-CN">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>

<body>

</body>
<script>
  /* 
    new Proxy(target,handler);
    let obj = new Proxy(被代理的对象,对代理的对象进行操作);
    handler: {
      set(){}, 设置这个对象的属性时执行的方法了
      get(){}, 获取这个对象的属性时执行的方法
      deleteProperty(){}, 删除对象时执行的方法
      has(){}, 判断对象中是否存在这个方法
      apply() 执行函数处理
    }

    new Proxy({},{
      get(target, property){},
      set(target,prop,value){},
      deleteProperty(target,property){
        delete xxx;
      },
      has(target,property){
        return
      },
      apply(target,context,args)
    });
  */
  class Person {
    constructor(name, age) {
      this.name = name;
      this.age = age;
    }
    hao() {
      return `大家好呀,我叫${this.name}`;
    }
  };

  let son = new Person("cz", 19);
  console.dir(son);

  let newObj = new Proxy(
    son, {
    get(target, property) {
      // return target[property]; 当访问对象的属性时，直接返回
      if (property in target) {
        return target[property];
      } else {
        // throw new ReferenceError(`${property}属性不在对象上`);
        console.error(`${property}属性不在对象上`);
        return `^_^`;
      };
    },
    set() {

    }
  });

  console.log(newObj.age);
</script>
<script>
  "use strict"; {
    const Dom = new Proxy({}, {
      get(target, property) {
        return (attar = {}, ...children) => {
          const ele = document.createElement(property);
          for (let [key, value] of Object.entries(attar)) {
            ele.setAttribute(key, value);
          };
          for (let item of children) {
            if (typeof item == "string") item = document.createTextNode(item);
            ele.appendChild(item);
          };
          return ele;
        };
      },
    });
    let div1 = Dom.div(
      { id: "dv", class: "cls" }, "我是第一个div的了吧", "你们看看我是谁",
      Dom.a({ href: "https://www.baidu.com" }, "访问官网"),
      Dom.ul({},
        Dom.li({}, "1111"),
        Dom.li({}, "2223"),
        Dom.li({}, "4566")
      )
    );
    console.log(div1);
    window.addEventListener("load", () => {
      document.body.appendChild(div1);
    });
  };
</script>
<script>
  // 使用proxy制作权限预检查
  /* 
    当用户的权限不是admin时，不能执行删除操作
  */
  "use strict"; {
    const requireAdminRole = (fn) => {
      return new Proxy(fn, {
        apply(target, context, args) {
          console.log(`target`, target);
          console.log(`context`, context);
          console.log(`args`, args);
          if (context.role === "admin") {
            target(context);
          } else {
            console.error(`这个权限不足不能删除哈哈哈`);
          };
        },
      });
    };
    const user = {
      role: "admin",
      // role: "normal",
      name: "zhangsan",
      delete_content: requireAdminRole(() => {
        console.log(`删除成功了吧`);
      })
    };

    user.delete_content();
  };

  // 深度监听对象、数组变化
  "use strict"; {
    /**
     * 对象、数组变化监听(增删改)
     * @author w-bing
     * @date 2020-04-22
     * @param {Object} obj
     * @param {Function} cb
     * @return {Proxy}
     */
    function deepProxy(obj, cb) {
      if (typeof obj === 'object') {
        for (let key in obj) {
          if (typeof obj[key] === 'object') {
            obj[key] = deepProxy(obj[key], cb);
          }
        }
      }
      return new Proxy(obj, {
        /**
         * @param {Object, Array} target 设置值的对象
         * @param {String} key 属性
         * @param {any} value 值
         * @param {Object} receiver this
         */
        set(target, key, value, receiver) {
          if (typeof value === 'object') {
            value = deepProxy(value, cb);
          }
          let cbType = target[key] == undefined ? 'create' : 'modify';
          //排除数组修改length回调
          if (!(Array.isArray(target) && key === 'length')) {
            cb(cbType, { target, key, value });
          }
          return Reflect.set(target, key, value, receiver);
        },
        deleteProperty(target, key) {
          cb('delete', { target, key });
          return Reflect.deleteProperty(target, key);
        }
      });
    }
  };
</script>

</html>